/*
 *  Copyright 2011 yura.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */
package org.opu.db_vdumper.ui.component.area.model;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.opu.db_vdumper.beans.ColumnBean;
import org.opu.db_vdumper.beans.TableBean;
import org.opu.db_vdumper.ui.ViewFactory;
import org.opu.db_vdumper.ui.component.tabel.models.TableModel;
import org.opu.db_vdumper.ui.component.tabel.models.ArrowModel;
import org.opu.db_vdumper.ui.component.tabel.models.Model;
import org.opu.db_vdumper.ui.component.tabel.models.SelectedComponent;
import org.opu.db_vdumper.ui.View;
import org.opu.db_vdumper.ui.i18n.TreeI18N;
import org.opu.db_vdumper.ui.i18n.TreeI18NImpl;
import org.opu.db_vdumper.util.Logger;

/**
 *
 * @author Potochnak Yana
 */
public class CanvesModel extends Model {

    private Set<Model> selectedComp;
    private List<TableModel> tables;
    private List<ArrowModel> arrows;
    private TreeI18N i18N;

    /**
     *  Create instance with empty set`s
     */
    public CanvesModel() {
        this.selectedComp = new HashSet<Model>();
        this.tables = new ArrayList<TableModel>();
        this.arrows = new ArrayList<ArrowModel>();
        this.i18N = new TreeI18NImpl();
    }

    /**
     *  If component already in set, it`s removed from
     * selected component, else it`s added to it. If
     * component change selection he will repain
     * @param comp processed component
     */
    public void addToSelected(SelectedComponent comp) {
        if (comp != null) {
            addToSelected(comp.getViewModel());
        }
    }

    public void setSelected(Model model, boolean selected){
        Logger.getInstance().debug(this, "Select " + model + " " + selected);
        
        if (selected){
            selectedComp.add(model);
        } else {
            selectedComp.remove(model);
        }

        model.setSelected(selected);

        if (model.hasChildrens()){
            Collection<Model> childrens = model.getChildrens();
            for (Model ch : childrens) {
                ch.setSelected(selected);
                if (selected){
                    selectedComp.add(ch);
                } else {
                    selectedComp.remove(ch);
                }
            }
        }
    }

    public void addToSelected(Model model) {
        if (selectedComp.contains(model)) {
            setSelected(model, false);
        } else {
            setSelected(model, true);
        }
    }


    /**
     *  Remove all components from set, and added current.
     * If this component is null, set will be empty!
     * @param comp processed component
     * @see #removeAllSelected() 
     */
    public void setSelected(SelectedComponent comp) {
        removeAllSelected();
        if (comp != null) {
            setSelected(comp.getViewModel(), true);
        }
    }

    /**
     *  Remove all components from set
     */
    public void removeAllSelected() {
        for (Model v : selectedComp) {
            if (v != null) {
                v.setSelected(false);
            }
        }
        selectedComp.clear();
    }

    public List<ArrowModel> getArrows() {
        return arrows;
    }

    public Set<Model> getSelectedComp() {
        return selectedComp;
    }

    public void setSelectedComp(Set<Model> selectedComp) {
        this.selectedComp = selectedComp;
    }

    public List<TableModel> getTables() {
        return tables;
    }

    public void setTablesBean(List<TableBean> beans) {
        List<TableModel> _tables = new ArrayList<TableModel>(beans.size());

        for (TableBean b : beans) {
            _tables.add(new TableModel(b));
        }

        this.setTables(_tables);
    }

    public void setTables(List<TableModel> tables) {
        // Creating tables list.
        this.tables.clear();
        this.tables.addAll(tables);
        this.selectedComp.clear();
        
        // Creating arrows list.
        this.arrows.clear();

        // Loop over all table
        for (TableModel tm : this.tables) {
            TableBean bean = tm.getBean();
            List<ColumnBean> columns = bean.getColumns();

            // Loop over columns in current table (knowing table bean)
            for (ColumnBean c : columns) {
                ColumnBean r = c.getReferences();

                // If current column has reference - need create arrow model and
                // add it to arrows list (doing almost the same that before).
                if (r != null){
                    for (TableModel tm2 : this.tables) {
                        for (ColumnBean c2 : tm2.getBean().getColumns()) {
                            if (r == c2){
                                this.arrows.add(ViewFactory.getInstance()
                                        .getArrowMethod().getArrowModel(c, tm, tm2));
                            }
                        }
                    }
                }

            }

        }

        logData();

        // Revalidate all views.
        repaint();
    }

    private void logData() {
        Logger log = Logger.getInstance();

        for (TableModel tableModel : tables) {
            log.debug(this, new StringBuilder().append(tableModel.getName())
                    .append(":").append(Arrays.asList(tableModel.attributesArray())));
        }

        for (ArrowModel arrow : arrows) {
            ColumnBean from = arrow.getFrom();
            ColumnBean to = arrow.getTo();
            log.debug(this, new StringBuilder().append(from.getTable().getName())
                    .append(".").append(from.getName()).append(" to ")
                    .append(to.getTable().getName()).append(".")
                    .append(to.getName()));
        }

    }

    @Override
    public boolean hasChildrens() {
        return !tables.isEmpty();
    }

    @Override
    public Collection<TableModel> getChildrens() {
        return tables;
    }

    @Override
    public void setSelected(boolean selected) {
        super.setSelected(selected);

        for (TableModel tbl : tables) {
            tbl.setSelected(selected);
        }
    }

    @Override
    public boolean isSelected() {
        for (TableModel tbl : tables) {
            if (tbl.isSelected()){
                return true;
            }
        }

        return false;
    }

    @Override
    public String toString() {
        return i18N.getDatabase();
    }

    public Model getDatabaseModel(){
        return new Model() {

            @Override
            public boolean hasChildrens() {
                return CanvesModel.this.hasChildrens();
            }

            @Override
            public Collection getChildrens(){
                return CanvesModel.this.getChildrens();
            }

            @Override
            public String toString() {
                return CanvesModel.this.toString();
            }
        };
    }

}
